using System;
using System.Collections.Generic;
using System.Text;
using SqlTools.CodeGenerator.Data;
using System.IO;

namespace SqlTools.CodeGenerator.CSharp
{
	public class PrimaryKeyGenerator
	{
		protected Table _table;

		public PrimaryKeyGenerator(Table table)
		{
			_table = table;
		}

		public void CreatePrimaryKey()
		{
			CodeBuilder cb = new CodeBuilder(_table.BusinessNamespace, _table.PrimaryKeyClassName);
			cb.PartialClass = _table.Project.UseGeneratedPartialClassFormat;

			GenerateUsingStatements(cb);

			if ( _table.BaseTable != null )
			{
				cb.Bases.Add(_table.BaseTable.PrimaryKeyClassName);
			}
			else
			{
				cb.Bases.Add("PrimaryKey");
			}



			PrimaryKeyTableProperty pktp = _table.GetPrimaryKey();

			if ( pktp != null )
			{
				GenerateFields(cb, pktp);

				cb.NewLine();

				GenerateDefaultConstructor(cb, pktp);

				cb.NewLine();

				if ( _table.BaseTable != null )
				{
					GenerateBaseDefaultConstructor(cb, pktp);

					cb.NewLine();
				}

				GenerateInitConstructor(cb, pktp);

				cb.NewLine();

				GenerateProperties(cb, pktp);
			}

			string fileText = cb.GetText();


			string fileName = Path.Combine(_table.Project.RootDirectory, _table.BusinessDirectory);

			Directory.CreateDirectory(fileName);

			string file = _table.PrimaryKeyClassName;

			if ( _table.Project.UseGeneratedPartialClassFormat )
				file += ".generated";

			file += ".cs";

			fileName = Path.Combine(fileName, file);

			StreamWriter sw = File.CreateText(fileName);
			sw.Write(fileText);
			sw.Close();

			if ( _table.Project.UseGeneratedPartialClassFormat )
			{
				// create edittable partial class

				fileName = Path.Combine(_table.Project.RootDirectory, _table.BusinessDirectory);

				file = _table.PrimaryKeyClassName;

				file += ".cs";

				fileName = Path.Combine(fileName, file);

				// check to see if file exists.  If it does, we do nothing

				if ( !File.Exists(fileName) )
				{

					cb = new CodeBuilder(_table.BusinessNamespace, _table.PrimaryKeyClassName);
					cb.PartialClass = true;

					GenerateUsingStatements(cb);

					fileText = cb.GetText();

					sw = File.CreateText(fileName);
					sw.Write(fileText);
					sw.Close();
				}

			}
		}

		private void GenerateProperties(CodeBuilder cb, PrimaryKeyTableProperty pktp)
		{
			bool first = true;
			pktp.Properties.OperateOnProperties(delegate(TableProperty tp)
			{
				if ( !first )
					cb.NewLine();
				else
					first = false;

				cb.BeginProperty(tp.CSharpDataType, tp.PropertyName);

				cb.AppendGet(tp.FieldName);
				cb.Append("internal set { ").Append(tp.FieldName).Append(" = value; }").NewLine();

				cb.EndProperty();
			}
			);
		}

		protected void GenerateUsingStatements(CodeBuilder cb)
		{
			cb.Namespaces.Add("System");
			cb.Namespaces.Add("System.Collections.Generic");
			cb.Namespaces.Add("System.Text");
			cb.Namespaces.Add("SqlTools.DataAccessLibrary");
		}

		protected void GenerateFields(CodeBuilder cb, PrimaryKeyTableProperty pktp)
		{
			pktp.Properties.OperateOnProperties(delegate(TableProperty tp)
			{
				cb.AppendField(AccessibilityLevel.Protected, tp.CSharpDataType, tp.FieldName);
			}
			);
		}

		protected void GenerateDefaultConstructor(CodeBuilder cb, PrimaryKeyTableProperty pktp)
		{

			cb.Append("public ").Append(_table.PrimaryKeyClassName).Append("()").NewLine();
            //TODOS GPC
			if(pktp.Properties.Count>0) 
                cb.SingleLineIndent().Append(": this(");
			bool first = true;

			foreach ( TableProperty prop in pktp.Properties )
			{
				if ( !first )
				{
					cb.Append(", ");
				}
				else
				{
					first = false;
				}
				cb.Append(prop.DefaultValue);
			}
            if (pktp.Properties.Count > 0) 
			   cb.Append(")").NewLine();
			cb.BeginBlock();
			cb.EndBlock();
		}

		private void GenerateBaseDefaultConstructor(CodeBuilder cb, PrimaryKeyTableProperty pktp)
		{
            //TODOS GPC
            if (pktp.Properties.Count == 0) return;

			cb.Append("public ").Append(_table.PrimaryKeyClassName).Append("(");
			bool first = true;

			foreach ( TableProperty prop in pktp.Properties )
			{
				if ( !first )
				{
					cb.Append(", ");
				}
				else
				{
					first = false;
				}
				cb.Append(prop.CSharpDataType).Append(" ").Append(NamingHelper.NonMemberName(prop.FieldName));
			}
			cb.Append(")").NewLine();

			cb.SingleLineIndent().Append(": this(");

			first = true;
			foreach ( TableProperty prop in pktp.Properties )
			{
				if ( !first )
				{
					cb.Append(", ");
				}
				else
				{
					first = false;
				}
				cb.Append(NamingHelper.NonMemberName(prop.FieldName));
			}

			// now add default values for base class pk props

			PrimaryKeyTableProperty bpktp = _table.BaseTable.GetPrimaryKey();
			if ( bpktp != null )
			{
				foreach ( TableProperty prop in bpktp.Properties )
				{
					if ( !first )
					{
						cb.Append(", ");
					}
					else
					{
						first = false;
					}
					cb.Append(prop.DefaultValue);
				}
			}
			cb.Append(")").NewLine();

			cb.BeginBlock();
			cb.EndBlock();
		}

		protected void GenerateInitConstructor(CodeBuilder cb, PrimaryKeyTableProperty pktp)
		{ 
            //TODOS GPC
            if(pktp.Properties.Count == 0) return;
			cb.Append("public ").Append(_table.PrimaryKeyClassName).Append("(");
			bool first = true;

			foreach ( TableProperty prop in pktp.Properties )
			{
				if ( !first )
				{
					cb.Append(", ");
				}
				else
				{
					first = false;
				}
				cb.Append(prop.CSharpDataType).Append(" ").Append(NamingHelper.NonMemberName(prop.FieldName));
			}

			// if theres a base table, loop through base table pk props
			if ( _table.BaseTable != null )
			{
				PrimaryKeyTableProperty bpktp = _table.BaseTable.GetPrimaryKey();
				if ( bpktp != null )
				{
					foreach ( TableProperty prop in bpktp.Properties )
					{
						if ( !first )
						{
							cb.Append(", ");
						}
						else
						{
							first = false;
						}
						cb.Append(prop.CSharpDataType).Append(" ").Append(NamingHelper.NonMemberName(prop.FieldName));
					}

				}
			}

			cb.Append(")").NewLine();

			// if base table, pass base table pk props to base class
			if ( _table.BaseTable != null )
			{
				PrimaryKeyTableProperty bpktp = _table.BaseTable.GetPrimaryKey();

				if ( bpktp != null )
				{
					cb.SingleLineIndent().Append(": base(");

					first = true;
					foreach ( TableProperty prop in bpktp.Properties )
					{
						if ( !first )
						{
							cb.Append(", ");
						}
						else
						{
							first = false;
						}
						cb.Append(NamingHelper.NonMemberName(prop.FieldName));
					}

					cb.Append(")").NewLine();
				}
			}

			cb.BeginBlock();

			foreach ( TableProperty prop in pktp.Properties )
			{
				cb.Append(prop.FieldName).Append(" = ").Append(NamingHelper.NonMemberName(prop.FieldName)).NewLine(true);
			}

			cb.NewLine();

			foreach ( TableProperty prop in pktp.Properties )
			{
				cb.Append("this.Columns.Add(").Append("\"").Append(prop.PropertyName).Append("\", ").Append(prop.FieldName).Append(")").NewLine(true);
			}

			cb.EndBlock();
		}
	}
}
